home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
term-source.lha
/
Extras
/
Source
/
term-Source.lha
/
termFileBuffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-17
|
22KB
|
1,113 lines
/*
** termFileBuffer.c
**
** Double-buffered file I/O routines
**
** Copyright © 1990-1995 by Olaf `Olsen' Barthel
** All Rights Reserved
*/
#include "termGlobal.h"
/* Argument types. */
enum { ARG_NAME,ARG_MODE };
enum { ARG_OFFSET,ARG_ORIGIN };
/* Seek offsets. */
enum { SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
/* Command codes. */
enum { BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
/* ObtainInfo(struct Buffer *File):
*
* Obtain information on the disk a buffered file
* resides on.
*/
STATIC VOID __regargs
ObtainInfo(struct Buffer *File)
{
/* Lock on the path available? */
if(File -> InfoPort)
{
/* This is more or less a trick; we try to obtain
* information on a filing system without having a
* shared lock on it. We cannot DupLockFromFH()
* the file handle since it was allocated for
* exclusive access. The ACTION_DISK_INFO packet
* solves this problem as it requires only the
* filing system task (MsgPort) to be given.
*/
if(!DoPkt1(File -> InfoPort,ACTION_DISK_INFO,MKBADDR(&File -> InfoData)))
{
File -> InfoData . id_NumBlocks = 0;
File -> InfoData . id_BytesPerBlock = 0;
}
}
}
/* FileBufferServer():
*
* Background process to handle the buffering
* of a filehandle, automatically gets invoked
* when a file is opened.
*/
STATIC VOID __saveds
FileBufferServer(VOID)
{
struct MsgPort *Port;
struct Buffer *Buffer;
BYTE Terminated = FALSE,
Done,
WasFull;
UBYTE *String;
APTR Data;
LONG Length;
BPTR SomeLock;
/* Wait for startup message (-> Buffer). */
Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
WaitPort(Port);
Buffer = (struct Buffer *)GetMsg(Port);
/* Open the file and obtain a filehandle. */
String = (STRPTR)Buffer -> ActionData[ARG_MODE];
Buffer -> WriteAccess = TRUE;
/* Put the message into the list. */
ObtainSemaphore(&DoubleBufferSemaphore);
AddTail(&DoubleBufferList,(struct Node *)Buffer);
ReleaseSemaphore(&DoubleBufferSemaphore);
/* Remember the opening date. */
DateStamp(&Buffer -> OpenDate);
/* Check for the open type. */
switch(String[0])
{
case 'r':
if(String[1] == '+')
Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
else
{
Buffer -> WriteAccess = FALSE;
Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
}
break;
case 'w':
if(String[1] == '+')
{
if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
{
UnLock(SomeLock);
DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
}
Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
}
else
Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
break;
case 'a':
if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
{
UnLock(SomeLock);
if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
{
if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
{
Close(Buffer -> FileHandle);
Buffer -> FileHandle = NULL;
}
}
}
else
Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
break;
}
/* Clear signal bit. */
ClrSignal(SIG_COMMAND);
/* Did the file open? */
if(Buffer -> FileHandle)
{
Buffer -> Data = Buffer -> DataBuffer[0];
Buffer -> DataCount = 1;
Buffer -> Fresh = TRUE;
/* If not in write mode fill the buffers. */
if(!Buffer -> WriteAccess)
{
/* Fill the first one synchronously. */
Buffer -> ReadBufFull = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
Buffer -> Read = TRUE;
Buffer -> RealPosition = Buffer -> ReadBufFull;
/* Restart caller. */
Signal(Buffer -> Caller,SIG_HANDSHAKE);
/* Fill the second buffe asynchronously. */
Buffer -> DataLength[1] = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
Buffer -> RealPosition += Buffer -> Cached;
}
else
{
Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
ObtainInfo(Buffer);
Signal(Buffer -> Caller,SIG_HANDSHAKE);
}
}
else
Terminated = TRUE;
/* Go into loop waiting for commands. */
while(!Terminated)
{
Wait(SIG_COMMAND);
Done = FALSE;
Buffer -> Result = 0;
/* Take care of each action. */
switch(Buffer -> Action)
{
/* Close the file, flush any dirty
* buffers and exit.
*/
case BUF_CLOSE:
Buffer -> Result = TRUE;
if(Buffer -> BufPosition && Buffer -> Written)
{
if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
Buffer -> Result = FALSE;
}
if(!Close(Buffer -> FileHandle))
Buffer -> Result = FALSE;
Terminated = TRUE;
break;
/* Seek to a specific file position. */
case BUF_SEEK:
Buffer -> Result = 0;
/* Do nothing if buffer is still
* untouched and we are required
* to seek back to the beginning
* of the file.
*/
if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEKFILE_SET)
{
Signal(Buffer -> Caller,SIG_HANDSHAKE);
Done = TRUE;
}
else
{
Buffer -> WriteBufFull = Buffer -> BufLength;
Buffer -> Read = FALSE;
if(Buffer -> BufPosition && Buffer -> Written)
{
if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
Buffer -> Result = -1;
else
ObtainInfo(Buffer);
}
if(!Buffer -> Result)
{
Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
switch(Buffer -> ActionData[ARG_ORIGIN])
{
case SEEKFILE_SET:
if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
else
Buffer -> Result = -1;
break;
case SEEKFILE_CURR:
if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
{
Buffer -> ReadBufFull -= Buffer -> ActionData[ARG_OFFSET];
Buffer -> Data += Buffer -> ActionData[ARG_OFFSET];
Signal(Buffer -> Caller,SIG_HANDSHAKE);
Done = TRUE;
break;
}
if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
else
Buffer -> Result = -1;
break;
case SEEKFILE_END:
if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
else
Buffer -> Result = -1;
break;
default:
Buffer -> Result = -1;
}
Buffer -> ReadBufFull = 0;
if(Buffer -> Result != -1)
{
Buffer -> Data = Buffer -> DataBuffer[0];
Buffer -> DataCount = 1;
if(!Buffer -> WriteAccess)
{
Buffer -> ReadBufFull = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
Buffer -> WriteBufFull = 0;
Buffer -> Read = TRUE;
Buffer -> RealPosition += Buffer -> ReadBufFull;
if(Buffer -> ReadBufFull)
{
Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
Buffer -> RealPosition += Buffer -> Cached;
}
}
}
else
Buffer -> LastActionFailed = TRUE;
}
else
Buffer -> ReadBufFull = 0;
Buffer -> BufPosition = 0;
Buffer -> Written = FALSE;
}
break;
/* Fill the buffer with fresh data. */
case BUF_FILL:
Buffer -> Data = Buffer -> DataBuffer[Buffer -> DataCount];
Buffer -> ReadBufFull = Buffer -> DataLength[Buffer -> DataCount];
Buffer -> WriteBufFull = 0;
Buffer -> BufPosition = 0;
Buffer -> Read = TRUE;
Buffer -> Written = FALSE;
Buffer -> Fresh = FALSE;
if(Buffer -> ReadBufFull)
WasFull = TRUE;
else
WasFull = FALSE;
/* The buffer contents have been
* swapped, now wake the caller
* up and fill the next buffer
* asynchronously.
*/
Signal(Buffer -> Caller,SIG_HANDSHAKE);
Done = TRUE;
if(WasFull)
{
Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
Buffer -> RealPosition += Buffer -> Cached;
if(!Buffer -> DataLength[Buffer -> DataCount])
{
if(IoErr())
Buffer -> LastActionFailed = TRUE;
}
}
break;
/* Flush the contents of the buffer to disk. */
case BUF_FLUSH:
if(Buffer -> BufPosition && Buffer -> Written)
{
Data = Buffer -> Data;
Length = Buffer -> BufPosition;
Buffer -> Data = Buffer -> DataBuffer[Buffer -> DataCount];
Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
Buffer -> ReadBufFull = 0;
Buffer -> WriteBufFull = Buffer -> BufLength;
Buffer -> BufPosition = 0;
Buffer -> Read = FALSE;
Buffer -> Written = FALSE;
Signal(Buffer -> Caller,SIG_HANDSHAKE);
Done = TRUE;
if(Write(Buffer -> FileHandle,Data,Length) != Length)
Buffer -> LastActionFailed = TRUE;
else
{
ObtainInfo(Buffer);
Buffer -> RealPosition += Length;
}
}
else
{
Buffer -> ReadBufFull = 0;
Buffer -> WriteBufFull = Buffer -> BufLength;
Buffer -> BufPosition = 0;
Buffer -> Read = FALSE;
Buffer -> Written = FALSE;
}
Buffer -> Fresh = FALSE;
break;
}
/* Ring back if necessary. */
if(!Done && !Terminated)
Signal(Buffer -> Caller,SIG_HANDSHAKE);
}
/* Remove the message from the list. */
ObtainSemaphore(&DoubleBufferSemaphore);
Remove((struct Node *)Buffer);
ReleaseSemaphore(&DoubleBufferSemaphore);
/* Lock & quit. */
Forbid();
Signal(Buffer -> Caller,SIG_HANDSHAKE);
}
/* BufferFill(struct Buffer *Buffer):
*
* Fills a given buffer with fresh data.
*/
STATIC BYTE __inline
BufferFill(struct Buffer *Buffer)
{
if(Buffer -> LastActionFailed)
return(FALSE);
else
{
if(!Buffer -> ReadBufFull)
{
Buffer -> Action = BUF_FILL;
Forbid();
Signal(Buffer -> Child,SIG_COMMAND);
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
}
return(TRUE);
}
}
/* IsValidBuffer(struct Buffer *Buffer):
*
* Scans the double buffered file list for
* a valid entry.
*/
STATIC BYTE __inline
IsValidBuffer(struct Buffer *Buffer)
{
BYTE GotIt = FALSE;
struct Node *Node;
ObtainSemaphore(&DoubleBufferSemaphore);
Node = DoubleBufferList . lh_Head;
while(Node -> ln_Succ)
{
if(Buffer == (struct Buffer *)Node)
{
GotIt = TRUE;
break;
}
Node = Node -> ln_Succ;
}
ReleaseSemaphore(&DoubleBufferSemaphore);
return(GotIt);
}
/* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
*
* Open simple (unbuffered) file.
*/
STATIC struct Buffer * __regargs
OpenFileSimple(STRPTR Name,STRPTR AccessMode)
{
struct Buffer *Buffer;
/* Allocate buffer handle (dummy). */
if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
{
BPTR SomeLock;
/* Provide basic information. */
DateStamp(&Buffer -> OpenDate);
Buffer -> WriteAccess = TRUE;
Buffer -> SimpleIO = TRUE;
/* Open the file. */
switch(AccessMode[0])
{
case 'r':
if(AccessMode[1] == '+')
Buffer -> FileHandle = Open(Name,MODE_READWRITE);
else
{
Buffer -> WriteAccess = FALSE;
Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
}
break;
case 'w':
if(AccessMode[1] == '+')
{
if(SomeLock = Lock(Name,ACCESS_WRITE))
{
UnLock(SomeLock);
DeleteFile(Name);
}
Buffer -> FileHandle = Open(Name,MODE_READWRITE);
}
else
Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
break;
case 'a':
if(SomeLock = Lock(Name,ACCESS_WRITE))
{
UnLock(SomeLock);
if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
{
if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
{
Close(Buffer -> FileHandle);
Buffer -> FileHandle = NULL;
}
}
}
else
Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
break;
}
/* Did we succeed in opening the file? */
if(Buffer -> FileHandle)
{
/* To keep track of the free space still
* available on the filing system.
*/
if(Buffer -> WriteAccess)
{
Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
ObtainInfo(Buffer);
}
/* Link the file into the list. */
ObtainSemaphore(&DoubleBufferSemaphore);
AddTail(&DoubleBufferList,(struct Node *)Buffer);
ReleaseSemaphore(&DoubleBufferSemaphore);
return(Buffer);
}
else
FreeVecPooled(Buffer);
}
return(NULL);
}
/* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
*
* Open double-buffered file.
*/
STATIC struct Buffer * __regargs
OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
{
struct Buffer *Buffer;
LONG Size;
Size = (Config -> MiscConfig -> IOBufferSize + 15) & ~15;
if(Size < 2048)
Size = 2048;
/* Allocate the buffer data. */
do
{
Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + ((Size + 15) & ~15) * BUFFER_NUMBER + 15,MEMF_ANY | MEMF_CLEAR);
Size /= 2;
}
while(!Buffer && Size > 2048);
if(Buffer)
{
struct Process *Process;
WORD i;
/* Set up the first buffer. */
Buffer -> DataBuffer[0] = (UBYTE *)(((ULONG)(Buffer + 1) + 15) & ~15);
/* Set up the individual buffers. */
for(i = 1 ; i < BUFFER_NUMBER ; i++)
Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + Size;
Buffer -> BufLength = Size;
Buffer -> WriteBufFull = Buffer -> BufLength;
/* Create the asynchronous file server. */
if(!(Process = CreateNewProcTags(
NP_Entry, FileBufferServer,
NP_Name, "term File Process",
NP_Priority, SysBase -> ThisTask -> tc_Node . ln_Pri,
NP_StackSize, 8192,
NP_WindowPtr, -1,
TAG_DONE)))
{
FreeVecPooled(Buffer);
return(NULL);
}
/* Set up the message header. */
Buffer -> Message . mn_Length = sizeof(struct Buffer);
Buffer -> ActionData[ARG_NAME] = (LONG)Name;
Buffer -> ActionData[ARG_MODE] = (LONG)AccessMode;
Buffer -> Child = Process;
Buffer -> Caller = (struct Process *)SysBase -> ThisTask;
Forbid();
/* Send it to the waiting server process. */
PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
/* Wait for ringback. */
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
/* Do we have a valid filehandle? */
if(!Buffer -> FileHandle)
{
FreeVecPooled(Buffer);
return(NULL);
}
else
return(Buffer);
}
return(NULL);
}
/* BPrintf():
*
* Prints text into a buffered file.
*/
LONG __stdargs
BPrintf(struct Buffer *Buffer,STRPTR Format,...)
{
UBYTE String[256];
va_list VarArgs;
va_start(VarArgs,Format);
VSPrintf(String,Format,VarArgs);
va_end(VarArgs);
return(BufferWrite(Buffer,String,strlen(String)));
}
/* BufferFlush(struct Buffer *Buffer):
*
* Flush the contents of a given buffer to disk.
*/
BYTE __regargs
BufferFlush(struct Buffer *Buffer)
{
if(Buffer -> LastActionFailed)
return(FALSE);
else
{
if(Buffer -> BufPosition && Buffer -> Written)
{
Buffer -> Action = BUF_FLUSH;
Forbid();
Signal(Buffer -> Child,SIG_COMMAND);
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
}
return(TRUE);
}
}
/* BufferClose(struct Buffer *Buffer):
*
* Close a buffered filehandle.
*/
BYTE __regargs
BufferClose(struct Buffer *Buffer)
{
if(IsValidBuffer(Buffer))
{
BYTE Success;
/* Unbuffered file handle? */
if(Buffer -> SimpleIO)
{
/* Close the file. */
if(Close(Buffer -> FileHandle))
Success = TRUE;
else
Success = FALSE;
/* Unlink the handle. */
ObtainSemaphore(&DoubleBufferSemaphore);
Remove((struct Node *)Buffer);
ReleaseSemaphore(&DoubleBufferSemaphore);
}
else
{
Buffer -> Action = BUF_CLOSE;
Forbid();
Signal(Buffer -> Child,SIG_COMMAND);
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
Success = Buffer -> Result;
}
FreeVecPooled(Buffer);
return(Success);
}
else
return(FALSE);
}
/* BufferOpen(STRPTR Name,STRPTR AccessMode):
*
* Open a file for buffered I/O.
*/
struct Buffer * __regargs
BufferOpen(STRPTR Name,STRPTR AccessMode)
{
/* Simple file handling? */
if(Config -> MiscConfig -> SimpleIO)
return(OpenFileSimple(Name,AccessMode));
else
{
struct Buffer *Buffer;
/* Try to open a buffered file, if unsuccessful
* fall back to simple file I/O.
*/
if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
Buffer = OpenFileSimple(Name,AccessMode);
return(Buffer);
}
}
/* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
*
* Move the read/write pointer to a specific position
* in a file (not really buffered).
*/
BYTE __regargs
BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
{
if(Buffer -> SimpleIO)
{
if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
return(FALSE);
else
return(TRUE);
}
else
{
Buffer -> Action = BUF_SEEK;
Buffer -> ActionData[ARG_OFFSET] = Offset;
Buffer -> ActionData[ARG_ORIGIN] = Origin;
Forbid();
Signal(Buffer -> Child,SIG_COMMAND);
ClrSignal(SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
if(Buffer -> Result == -1)
return(FALSE);
else
return(TRUE);
}
}
/* BufferRead():
*
* Read data from a file (buffered).
*/
LONG __regargs
BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
{
if(Buffer -> SimpleIO)
{
LONG Bytes;
Buffer -> Used = TRUE;
if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
Bytes = 0;
return(Bytes);
}
else
{
LONG BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
UBYTE *Data;
/* If there is still data to be written in
* the buffer, write it.
*/
if(Buffer -> Written)
{
if(!BufferFlush(Buffer))
return(0);
}
/* Set up for read access. */
BufPosition = Buffer -> BufPosition;
ReadBufFull = Buffer -> ReadBufFull;
Data = &Buffer -> Data[BufPosition];
/* Remember access. */
Buffer -> Used = TRUE;
/* Continue until all data has been processed. */
while(Size)
{
/* Determine number of bytes to transfer. */
if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
{
CopyMem(Data,Destination,ToCopy);
Size -= ToCopy;
BufPosition += ToCopy;
ReadBufFull -= ToCopy;
Destination += ToCopy;
Data += ToCopy;
BytesRead += ToCopy;
}
else
{
/* Refill buffer with data. */
Buffer -> BufPosition = BufPosition;
Buffer -> ReadBufFull = ReadBufFull;
if(!BufferFill(Buffer))
return(BytesRead);
if(!Buffer -> ReadBufFull)
{
Buffer -> BufPosition = BufPosition;
return(BytesRead);
}
/* Pick up new data. */
BufPosition = Buffer -> BufPosition;
ReadBufFull = Buffer -> ReadBufFull;
Data = Buffer -> Data;
}
}
/* Install new data. */
Buffer -> BufPosition = BufPosition;
Buffer -> ReadBufFull = ReadBufFull;
return(BytesRead);
}
}
/* BufferWrite():
*
* Write data to a file (buffered).
*/
LONG __regargs
BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
{
if(Buffer -> SimpleIO)
{
LONG Bytes;
Buffer -> Used = TRUE;
Buffer -> WriteAccess = TRUE;
if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
Bytes = 0;
else
{
Buffer -> BufPosition += Bytes;
if(Buffer -> BufPosition >= Config -> MiscConfig -> IOBufferSize)
{
Buffer -> BufPosition = 0;
ObtainInfo(Buffer);
}
}
return(Bytes);
}
else
{
LONG BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
UBYTE *Data;
/* If there is still read data in the buffer,
* reset the control information.
*/
if(Buffer -> Read)
{
Buffer -> WriteBufFull = Buffer -> BufLength;
Buffer -> BufPosition = 0;
Buffer -> Read = FALSE;
}
/* Set up for write access. */
Buffer -> Written = TRUE;
BufPosition = Buffer -> BufPosition;
WriteBufFull = Buffer -> WriteBufFull;
Data = &Buffer -> Data[BufPosition];
/* Remember access. */
Buffer -> Used = TRUE;
/* Continue until all data has been processed. */
while(Size)
{
/* Determine number of bytes to transfer. */
if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
{
CopyMem(Source,Data,ToCopy);
Size -= ToCopy;
BufPosition += ToCopy;
WriteBufFull -= ToCopy;
Source += ToCopy;
Data += ToCopy;
BytesWritten += ToCopy;
}
else
{
/* Flush the contents of the
* write buffer.
*/
Buffer -> BufPosition = BufPosition;
Buffer -> WriteBufFull = WriteBufFull;
if(!BufferFlush(Buffer))
return(BytesWritten);
/* Pick up new data. */
BufPosition = Buffer -> BufPosition;
WriteBufFull = Buffer -> WriteBufFull;
Data = Buffer -> Data;
/* Important - or BufferFlush() won't
* write the final buffer contents when
* the buffered file handle is freed up.
*/
Buffer -> Written = TRUE;
}
}
/* Install new data. */
Buffer -> BufPosition = BufPosition;
Buffer -> WriteBufFull = WriteBufFull;
return(BytesWritten);
}
}